﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;

namespace Fly.Common.Helper
{
    /// <summary>
    /// 字符串压缩辅助类
    /// </summary>
    public static class Compression
    {
        #region 压缩

        /// <summary>
        /// 压缩指定的 Byte 数组
        /// </summary>
        /// <param name="data">需要压缩的数据</param>
        /// <param name="compressionType">压缩方式</param>
        /// <returns>压缩后的数据</returns>
        [SuppressMessage("Microsoft.Usage", "CA2202:DoNotDisposeObjectsMultipleTimes")]
        public static byte[] Compress(byte[] data, CompressionType compressionType = CompressionType.Deflate)
        {
            Contract.Requires<ArgumentNullException>(data != null, "Data");
            using (MemoryStream stream = new MemoryStream())
            {
                using (Stream zipStream = GetStream(stream, CompressionMode.Compress, compressionType))
                {
                    zipStream.Write(data, 0, data.Length);
                    zipStream.Close();
                    return stream.ToArray();
                }
            }
        }

        /// <summary>
        /// 压缩一个字符串,返回压缩后的 Base64 编码的字符串
        /// </summary>
        /// <param name="data">需要压缩的数据</param>
        /// <param name="encodingUsing">压缩数据使用的编码,默认是 UTF-8</param>
        /// <param name="compressionType">压缩方式</param>
        /// <returns>The data Compressed</returns>
        public static string Compress(string data, Encoding encodingUsing = null, CompressionType compressionType = CompressionType.Deflate)
        {
            Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(data), "data");
            if (encodingUsing == null)
            {
                encodingUsing = new UTF8Encoding(false);
            }
            return Convert.ToBase64String(Compress(encodingUsing.GetBytes(data), compressionType),Base64FormattingOptions.None);
        }

        #endregion

        #region 解压缩

        /// <summary>
        /// 解压缩一个 Byte 数组
        /// </summary>
        /// <param name="data">需要解压缩的数据源</param>
        /// <param name="compressionType">解压缩的类型</param>
        /// <returns>The data decompressed</returns>
        [SuppressMessage("Microsoft.Usage", "CA2202:DoNotDisposeObjectsMultipleTimes")]
        public static byte[] Decompress(this byte[] data, CompressionType compressionType = CompressionType.Deflate)
        {
            Contract.Requires<ArgumentNullException>(data != null, "Data");
            using (MemoryStream stream = new MemoryStream())
            {
                using (MemoryStream dataStream = new MemoryStream(data))
                {
                    using (Stream zipStream = GetStream(dataStream, CompressionMode.Decompress, compressionType))
                    {
                        byte[] buffer = new byte[4096];
                        while (true)
                        {
                            int size = zipStream.Read(buffer, 0, buffer.Length);
                            if (size > 0) stream.Write(buffer, 0, size);
                            else break;
                        }
                        zipStream.Close();
                        return stream.ToArray();
                    }
                }
            }
        }

        /// <summary>
        /// 加压缩一个经过压缩的字符串,该字符串经过 Base64 编码
        /// </summary>
        /// <param name="data">源数据</param>
        /// <param name="encodingUsing">字符串的编码方式,默认使用 UTF-8 编码</param>
        /// <param name="compressionType">解压缩的类型</param>
        /// <returns>The data decompressed</returns>
        public static string Decompress(string data, Encoding encodingUsing = null, CompressionType compressionType = CompressionType.Deflate)
        {
            Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(data), "data");
            if (encodingUsing == null)
            {
                encodingUsing = new UTF8Encoding(false);
            }
            return encodingUsing.GetString(Decompress(Convert.FromBase64String(data), compressionType));
        }

        #endregion

        #region GetStream
        /// <summary>
        /// 对内存流进行压缩
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="mode"></param>
        /// <param name="compressionType"></param>
        /// <returns></returns>
        private static Stream GetStream(MemoryStream stream, CompressionMode mode, CompressionType compressionType)
        {
            if (compressionType == CompressionType.Deflate)
            {
                return new DeflateStream(stream, mode, true);
            }
            return new GZipStream(stream, mode, true);
        }

        #endregion
    }

    #region 压缩方式枚举
    /// <summary>
    ///压缩方式枚举
    /// </summary>
    public enum CompressionType
    {
        /// <summary>
        /// Deflate 压缩
        /// </summary>
        Deflate = 0,
        /// <summary>
        /// GZip 压缩
        /// </summary>
        GZip = 1
    } 
    #endregion
}
